
// global object containing all FreeTextBox objects
Refresh.Web.FreeTextBoxList = [];
Refresh.Web.CurrentFreeTextBox = null;

// default options
Refresh.Web.DefaultFreeTextBoxSettings = {
	width: null,
	height: null,
	styleSheetUrls: [],
	theme: Refresh.defaultTheme,
	breakMode: FTB_BREAKMODE_P,
	bodyID: '',
	bodyCssClass: '',
	cssPrefix: '',
	baseUrl: '',
	baseFont: '',
	language: 'en-US',
	isToolbarVisible: true,
	isStatusVisible: true,
	tabMode: FTB_TABMODE_EXIT,
	tabIndex: -1,
	isFullDocument: false,
	docType: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
	autoFormat: true,
	toolbarUpdateInterval: 400,
	toolbarGroups: null,
	textDirection:'ltr',
	galleryUrl: 'pro-filegallery.html',
	rootGalleryFolder: '',
	isSafari2Supported: true
};

Refresh.Web.FreeTextBox = Class.create();
Refresh.Web.FreeTextBox.prototype = {

	_allowRevert: false,	
	_toolbars: null,
	_changeEvents: null,
	_mode: FTB_MODE_DESIGN,
	_hasFocus: false,
	initialized: false,
	
	// Constructor
	initialize: function(id, settings) {		
		
		// check browser
		this.browser = Refresh.Web.BrowserInfo;
		// set values
		this.id = id;
		this.settings = Object.extend(Object.extend({},Refresh.Web.DefaultFreeTextBoxSettings), settings || {});
		
		if (!this.browser.isRich || (this.browser.isSafari2 && !this.settings.isSafari2Supported) ) {			
			return;	
		}
	
		this._toolbars = [];
		this._changeEvents = [];
		
		Refresh.Utility.ensureTheme(this.settings.theme);
		Refresh.Utility.ensureLanguage(this.settings.language);
		var ftb = this;
		Refresh.Web.FreeTextBoxList.push(ftb);

		// check for existing DOM Objects -OR- create HTML
		var design = $(this.id + '_Editor');
		
		// create DOM objects if not there
		if (design == null) {
			var objToConvert = $(this.id);
			if (objToConvert == null) {
				
				return;
			}			

			var codeEditor = null;

			if (objToConvert.tagName.toLowerCase() == 'textarea') {
				codeEditor = objToConvert;
			} else if (objToConvert.tagName.toLowerCase() == 'input') {
				codeEditor = document.createElement('textarea');
				codeEditor.value = objToConvert.value;
			} else if (objToConvert.tagName.toLowerCase() == 'div') {
				this._allowRevert = true;
				this.orginalElement = objToConvert;
				codeEditor = document.createElement('textarea');
				codeEditor.value = objToConvert.innerHTML;
			} else {
				alert(id + ' is not a supported element');
				return;
			}
			
			// first get size by style
			var objSize = {width: 0, height:0};						
			objSize.width = objToConvert.style.width;
			objSize.height = objToConvert.style.height;
			
			// if the style is missing, then measure the size
			var objDim = Element.getDimensions(objToConvert);
			if (objSize.width == '')
				objSize.width = objDim.width + 'px';
			if (objSize.height == '')
				objSize.height = objDim.height + 'px';			
			
			// if the developer didn't specify dimensions in the settings, then use the original object's size
			if (!this.settings.width)
				this.settings.width = objSize.width;
			if (!this.settings.height)
				this.settings.height = objSize.height;
			

			
			codeEditor.style.border = 0;
			codeEditor.style.padding = 0;
			codeEditor.style.margin = 0;
			codeEditor.style.background = 'transparent';
			codeEditor.style.width = 0;
			codeEditor.style.height = 0;
			//codeEditor.display = 'none';
			if (this.browser.isGecko)
				codeEditor.setAttribute('wrap','off');
			else
				codeEditor.wrap='off';

			// build surrounding table
			this.node = Refresh.Web.HTML.create('table', {id: this.id + '_EditorTable', cellPadding: 0, cellSpacing: 0, border: 0, className: this.settings.cssPrefix + 'editor'});						
			var tbody = Refresh.Web.HTML.append(this.node, 'tbody');
			
			// add toolbar row
			var toolRow = Refresh.Web.HTML.append(tbody, 'tr');
			var toolCell = Refresh.Web.HTML.append(toolRow, 'td');
			this.toolbarNode = Refresh.Web.HTML.append(toolCell, 'div', {id: this.id + '_EditorToolbars', className: this.settings.cssPrefix + 'editorToolbars'});
			toolRow.style.display = (this.settings.isToolbarVisible) ? '' : 'none';
			
			// add editor row
			var editorRow = Refresh.Web.HTML.append(tbody, 'tr');
			var editorCell = Refresh.Web.HTML.append(editorRow, 'td');
			var editorDiv = Refresh.Web.HTML.append(editorCell, 'div', {id: this.id + '_EditorContainer', className: this.settings.cssPrefix + 'editorContainer' + ' ' + this.settings.cssPrefix + 'editorContainer_Blur'});
			
		

			// create IFRAME
			var iframe = document.createElement('iframe');
			editorDiv.appendChild(iframe);
			iframe.setAttribute('id',this.id + '_Editor');
			iframe.style.border = '0';
			iframe.style.padding = '0';
			iframe.style.margin = '0';
			iframe.style.background = 'transparent';
			iframe.src = Refresh.windowPath + 'blank.html';	
			
			// add tabs 
			if (this.settings.isStatusVisible) {
				var tabsRow = Refresh.Web.HTML.append(tbody, 'tr');
				var tabsCell = Refresh.Web.HTML.append(tabsRow, 'td');
				var statusDiv = Refresh.Web.HTML.append(tabsCell, 'div', {id: this.id + '_EditorStatusBar', className: this.settings.cssPrefix + 'editorStatusBar'});
				var designTab = Refresh.Web.HTML.append(statusDiv, 'div', {id: this.id + '_DesignTab', className: this.settings.cssPrefix + 'editorTab ' + this.settings.cssPrefix + 'editorTabDesign'});
				var htmlTab = Refresh.Web.HTML.append(statusDiv, 'div', {id: this.id + '_CodeTab', className: this.settings.cssPrefix + 'editorTab ' + this.settings.cssPrefix + 'editorTabCode'});
				var statusArea = Refresh.Web.HTML.append(statusDiv, 'div', {id: this.id + '_Status', className: this.settings.cssPrefix + 'editorStatus'});
				var clear = Refresh.Web.HTML.append(statusDiv, 'div');			
				clear.style.clear = 'both';
			}
			
			// add table to page
			objToConvert.parentNode.insertBefore(this.node, objToConvert);
			
			// move textarea to inside table
			editorDiv.insertBefore(codeEditor, iframe);
			//editorDiv.appendChild(codeEditor);
			
			if (codeEditor != objToConvert) {
				objToConvert.parentNode.removeChild(objToConvert);
				//objToConvert.style.display = 'none';
				codeEditor.setAttribute('id',this.id);
				codeEditor.setAttribute('name',this.id);
			}
		}

		// attach DOM objects to this instance
		this._designEditor = $(this.id + '_Editor');
		this._codeEditor = $(this.id);
		this._editorContainer = $(this.id + '_EditorContainer');
		this._editorTable = $(this.id + '_EditorTable');

		this._editorTable.style.width = this.settings.width;

		this._editorContainer.style.width = this.settings.width;
		this._editorContainer.style.height = this.settings.height;

		this._codeEditor.style.width = 0;
		this._codeEditor.style.height = 0;
		//this._codeEditor.style.display = 'none';

		// store start value
		this._startValue = this._codeEditor.value;

		// setup tab enabled text editor
		var code = new CodeEditor(this.id);

		this._designEditor.style.width = this.settings.width; // '100%';
		this._designEditor.style.height = this.settings.height;

		this._addedEvents = {};
						
		this.initializeEditor();
	},
	
	initializeEditor: function() {
		/*
		if (!Refresh.Web.Localization.hasLanguage(this.settings.language)) {
			setTimeout( "" + this.id + ".initializeEditor()", 150);
			return;
		}
		*/
		
		// write HTML
		var stylesheets = '';
		for (var i=0; i<this.settings.styleSheetUrls.length; i++) {
			if (this.settings.styleSheetUrls[i] != '')
				stylesheets += '<link rel="stylesheet" type="text/css" href="' + this.settings.styleSheetUrls[i] + '" />';
				
			
		}
		
		var initialHtml = this._codeEditor.value;
		
		// check for HTML tag and set to full document mode
		if (!this.settings.isFullDocument && initialHtml.indexOf('<html>') > -1) {
			this.settings.isFullDocument = true;			
		}
		
		var html = '';
		
		if (this.settings.isFullDocument) {
			
						
			html = initialHtml;					
		} else {
		
			html = 
			this.settings.docType +
			'<html xmlns="http://www.w3.org/1999/xhtml">' +
				'<head>' +
						stylesheets +
						'<style type="text/css" id="HelperCss">' +
						'.ftb_table_helper { border: dashed 1px #ccc; border-width: 1px 1px 0 0; } .ftb_table_helper td { border: dashed 1px #ccc; border-width: 0 0 1px 1px; }' +
						'.ftb_misspelled { border-bottom: dotted 1px #f00; cursor: hand; cursor: arrow; }' +
						'</style>' +
				'</head>' +
				'<body' + ((this.settings.bodyID != '') ? ' id="' + this.settings.bodyID + '"'  : '') + ((this.settings.bodyCssClass != '') ? ' class="' + this.settings.bodyCssClass + '"'  : '') + ((this.settings.textDirection == 'rtl') ? ' dir="rtl"'  : '') + '>' +
					this._storeUrls(this._codeEditor.value) +
				'</body>' +
			'</html>';
		}
		
		try {

			this._designEditor.contentWindow.document.designMode = 'on';

			this._designEditor.contentWindow.document.open();
			this._designEditor.contentWindow.document.write(html);
			this._designEditor.contentWindow.document.close();
		
		} catch (ex) {
			
			
			try {
				this._designEditor.src = Refresh.path + 'html/blank.html';
			} catch (ex2) {
				
			}
			setTimeout( "" + this.id + ".initializeEditor()", 500);
			return;
		}
		
		// TEXT AREA EVENTS
	    this._event_onTextFocus = this._onTextFocus.bindAsEventListener(this);
	    this._event_onTextBlur = this._onTextBlur.bindAsEventListener(this);
		Event.observe(this._codeEditor, 'focus', this._event_onTextFocus);
		Event.observe(this._codeEditor, 'blur', this._event_onTextBlur);
		
		// TAB INDEX
		if (this.settings.tabIndex > -1) {
			this._codeEditor.tabIndex = tabIndex;
		} else if (!isNaN(this._codeEditor.tabIndex)) {
			this.settings.tabIndex = parseInt(this._codeEditor.tabIndex);
		}
		
		if (this.settings.tabIndex > -1) {
			
								
			// find ee								
			var formElements = document.getElementsByTagName('input');
			//formElements.concat(document.getElementsByTagName('select'));
			//formElements.concat(document.getElementsByTagName('textarea'));
			
			var nextElement = null;
			var prevElement = null;
						
			for (var t=0; t<formElements.length; t++) {
				var el = formElements[t];
				if (el != this._codeEditor) {
					if (nextElement == null) {
						if ( el.tabIndex > this.settings.tabIndex) {
							nextElement = el;
						}						
					} else {
						if ( el.tabIndex > this.settings.tabIndex && el.tabIndex < nextElement.tabIndex ) {
							nextElement = el;
						}					
					}	
					
					if (prevElement == null) {
						if ( el.tabIndex < this.settings.tabIndex) {
							prevElement = el;
						}						
					} else {
						if ( el.tabIndex < this.settings.tabIndex && nextElement != null && el.tabIndex > nextElement.tabIndex ) {
							prevElement = el;
						}					
					}																		
				}
			}
			
			if (nextElement != null)
				this.nextElement = nextElement;
			
			
		}
		
		
	    this._event_onDesignFocus = this._onDesignFocus.bindAsEventListener(this);
	    this._event_onDesignBlur = this._onDesignBlur.bindAsEventListener(this);		
	    this._event_onEvent = this._onEvent.bindAsEventListener(this);
		
		this._event_onPauseTimeout = this.onPauseTimeout.bindAsEventListener(this);

		// DESIGN AREA EVENTS
		var objToBind = null;
		if (this.browser.isIE || this.browser.isOpera ) {
			objToBind = this._designEditor.contentWindow.document.body;			
			
			if (this.browser.isIE) {
				Event.observe(objToBind, 'blur', this._event_onDesignBlur);
			} else if (this.browser.isOpera) {
				Event.observe(this._designEditor.contentWindow.document, 'blur', this._event_onDesignBlur);
			}
						
			Event.observe(objToBind, "keydown", this._event_onEvent);
			Event.observe(objToBind, "mousedown", this._event_onEvent);
			Event.observe(objToBind, "mouseup", this._event_onEvent);
			Event.observe(objToBind, "keyup", this._event_onEvent);	
			
			Event.observe(objToBind, "dblclick", this._event_onEvent);				
		} else {
			objToBind = this._designEditor.contentWindow;


			Event.observe(objToBind.document, 'blur', this._event_onDesignBlur);			
			Event.observe(objToBind, "keydown", this._event_onEvent);
			Event.observe(objToBind, "mousedown", this._event_onEvent);
			Event.observe(objToBind, "mouseup", this._event_onEvent);
			Event.observe(objToBind, "keyup", this._event_onEvent);		
			
			Event.observe(objToBind.document, "dblclick", this._event_onEvent);			
		}
		
		if (this.browser.isIE) {
			this._designEditor.contentWindow.document.body.style.border = 0;
		}
		
		// tabs
		this._designTab = $(this.id + '_DesignTab');
		if (this._designTab) {			
			
			this._designTab.innerHTML = Refresh.Web.Localization.getValue('designModeTab',this.settings.language);
			
			Event.observe(this._designTab, 'click', this.handleDesignModeTabClick.bindAsEventListener(this));
			Element.addClassName(this._designTab, 'editorTab_On');

			Refresh.Utility.makeUnselectable(this._designTab);
		}
		
		this._codeTab = $(this.id + '_CodeTab');
		if (this._codeTab) {
			this._codeTab.innerHTML = Refresh.Web.Localization.getValue('htmlModeTab',this.settings.language);
			
			Event.observe(this._codeTab, 'click', this.handleCodeModeTabClick.bindAsEventListener(this));
			Element.removeClassName(this._codeTab, 'editorTab_Off');			

			Refresh.Utility.makeUnselectable(this._codeTab);
		}

		// status bar (words)
		this._status = $(this.id + '_Status');

		// MOZ CSS Change
		if (this.browser.isGecko) {
			try {
				this._designEditor.contentWindow.document.execCommand("useCSS",null,true);
			} catch (ex) {}
		}

		// hook up to form
		var forms = document.getElementsByTagName('form');
		for (var i=0; i<forms.length; i++) {
			//Event.observe(forms[i], 'submit', this._onSubmit.bindAsEventListener(this) );
			if (forms[i].onsubmit)
				forms[i].ftbSubmit = forms[i].onsubmit;
			forms[i].onsubmit = this._onSubmit.bindAsEventListener(this);
		}

		// undo/redo setup
		this._typingEvent = false;
		this.maxUndoSteps = 20;

		this.undoIndex = 0;
		this.undoSteps = new Array();
		this.undoStepsText = new Array();
		this.undoSteps[this.undoIndex] = this._codeEditor.value;
		this.undoStepsText[this.undoIndex] = "startup";
		
		if (this.settings.toolbarGroups != null)		 {
			this.builtInToolbar = new Refresh.Web.Toolbar(this.id + '_Toolbar', {groups: this.settings.toolbarGroups, theme: this.settings.theme, target: this.toolbarNode});
			this.builtInToolbar.associateEditor(this);
		}

		// startup
		this.updateWordCount();
		this.updateToolbars();
		this.blur();
		this.initialized = true;		
  	},

	/* used with convert to allow switching between a div/textarea and an editor */
	revert: function() {	
		// TODO
		alert('not implimented');
	},		
	
	/* used with revert to allow switching between a div/textarea and an editor */
	convert: function() {	
		// TODO
		alert('not implimented');
		// this.initialize(this.settings);
	},			
	
	getHtml: function() {
		if (this._mode == FTB_MODE_DESIGN) {;
			if (this.settings.isFullDocument) {
				html = this.settings.docType + '\n' + 
					Refresh.Web.HtmlCleaner.validateNode( this._designEditor.contentWindow.document.getElementsByTagName('html')[0], this.settings.isFullDocument, this.settings.autoFormat, true );			
			} else {
				html = Refresh.Web.HtmlCleaner.validateNode(this._designEditor.contentWindow.document.body, this.settings.isFullDocument, this.settings.autoFormat, true);			
			}
			return html;		
		} else {
			return this._codeEditor.value;
		}
	},
	
	getQuickHtml: function() {
		if (this._mode == FTB_MODE_DESIGN) {
			if (this.settings.isFullDocument) {
				html = this.settings.docType + '\n' + 
					this._designEditor.contentWindow.document.getElementsByTagName('html')[0].innerHTML;
			} else {
				html = this._designEditor.contentWindow.document.body.innerHTML;
			}
		
			return html;
		} else {
			return this._codeEditor.value;
		}
	},	

	setHtml: function(html) {

		this._codeEditor.value = html;

		if (this._mode == FTB_MODE_DESIGN) {

			this._designEditor.contentWindow.document.body.innerHTML = this._codeEditor.value;
			this._addUndoStep('HTML Set');
			this.saveData();

		}
	},
	
	_storeUrls: function(input) {
		// store urls in temporary attribute (if not already done)
		if (!input.match(/(temp_src|temp_href)/gi, input)) {
			input = input.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" temp_src="$1"');
			input = input.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" temp_href="$1"');
		}
		return input;
	},

	removeTempUrls: function(input) {	
		input = input.replace(new RegExp('\\s*temp_src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), '');
		input = input.replace(new RegExp('\\s*temp_href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), '');
		return input;
	},	

	insertLink: function(url, target, title) {
		if (url != null && url != '') {
									
			this.focus();
			var link = this.getNearest('a');

			if (link == null) {
			
				
				if (this.browser.isSafari2) {
					var fakeFont = 'Safari2CantCreateALink';
					this.executeCommand('fontname',fakeFont);
					//return;
					var fontTags = this._getDocument().getElementsByTagName('font');
					var fontTag = null;
					for (var i=0;i<fontTags.length;i++) {						
						if (fontTags[i].face == fakeFont) {
							fontTag = fontTags[i];
							break;
						}
					}
					
					console.log('found font tag', (fontTag != null) );
					
					link = this._getDocument().createElement('a');
					link.innerHTML = fontTag.innerHTML;
					
					fontTag.parentNode.insertBefore(link, fontTag);
					fontTag.parentNode.removeChild(fontTag);
					
					console.log('new link', link);
										
				} else {
				
					var tempUrl = 'http://tempuri.org/tempuri.html';
					this.executeCommand('createLink',tempUrl);
					//return;
					var links = this._getDocument().getElementsByTagName('a');
					for (var i=0;i<links.length;i++) {
						if (links[i].href == tempUrl) {
							link = links[i];
							break;
						}
					}					
				}	
			

			
			}

			if (link != null) {
				link.href = url;
				link.setAttribute('temp_href',url);
				if (target != '')
					link.target = target;
				if (title != '')
					link.title = title;
	
	
				this._addUndoStep();
				this.quickSaveData();
				
			} else {
				
			}
		}
	},

	insertImage: function(imgSrc,width,height,alt,title) {
		if (imgSrc != null && imgSrc != '') {
			var img = this.getNearest('img');

			if (!img) {
				var tempUrl = 'http://tempuri.org/tempuri.html';
				this.executeCommand('insertimage',tempUrl);
				var imgs = this._getDocument().getElementsByTagName('img');
				for (var i=0;i<imgs.length;i++) {
					if (imgs[i].src == tempUrl) {
						img = imgs[i];
						break;
					}
				}
			}
			img.src = imgSrc;
			img.setAttribute('temp_src',imgSrc);

			if (width != '') {
				img.width = width;
			}
			if (height != '') {
				img.height = height;
			}
			if (alt != '') {
				img.alt = alt;
			}
			if (title != '') {
				img.title = title;
			}			
			/*
			if (vspace != '') {
				img.vspace = vspace;
			}
			if (vspace != '') {
				img.hspace = hspace;
            }
            */
			this._addUndoStep();
			this.quickSaveData();
			
			
			return img;
		}
	},

	_addUndoStep: function(action) {
		if (!action)
			action = 'unknown';

		var html = this._getDocument().body.innerHTML;

		// check to make sure there was a change
		if (html != this.undoSteps[this.undoIndex]) {

			// remove "future" steps if after a redo
			for (var i=this.undoIndex+1; i < this.undoSteps.length ; i++) {
				this.undoSteps.pop();
				this.undoStepsText.pop();
			}

			// add to undo array
			this.undoSteps.push(html);
			this.undoStepsText.push(action);

			// slice if too big
			if (this.maxUndoSteps > 0 && this.undoSteps.length > this.maxUndoSteps) {
				this.undoSteps = this.undoSteps.slice(1);
				this.undoStepsText = this.undoStepsText.slice(1);
			}

			this.undoIndex = this.undoSteps.length-1;
		}
	},

	undo: function() {

		if (this.undoIndex > 0 && this.undoSteps[this.undoIndex] != null) {
			this._codeEditor.value = this.undoSteps[this.undoIndex-1];
			this.undoIndex--;
			this._designEditor.contentWindow.document.body.innerHTML = this._codeEditor.value;
		}
	},

	redo: function() {

		if (this.undoIndex > -1 && this.undoIndex < this.undoSteps.length-1) {
			this._codeEditor.value = this.undoSteps[this.undoIndex+1];
			this.undoIndex++;
			this._designEditor.contentWindow.document.body.innerHTML = this._codeEditor.value;
			this.focus();
		}
	},

	print: function() {
		this._designEditor.contentWindow.print();
	},

  	focus: function() {
		
		
		// TODO re-select IE
		if (this.browser.isIE) {			
			this._getDocument().body.focus();
			
		} else if (this.browser.isGecko) {
			this._designEditor.contentWindow.focus();
			
		} else if (this.browser.isOpera) {
			
			if (this._bookmark) {
				this.selectBookmark(this._bookmark);
			}
			//this._designEditor.focus();
		} else if (this.browser.isSafari) {
			
			if (this._bookmark) {
				this.selectBookmark(this._bookmark);
			}
						
		}

		if (!this._hasFocus) {
  			this._onDesignFocus({type:'manualFocus'});
  		}
  	},
	
	_onTextFocus: function(event) {
		
		
		
		if (this._mode == FTB_MODE_DESIGN) {
			this.focus();
		} else {
			this._onDesignFocus(event);
		}
	},
	
	_onTextBlur: function(event) {
		//this.blur();
		// do nothing for now
		//if (this._mode == FTB_MODE_DESIGN)	
		//this.focus();	
	},	

	_onDesignFocus: function(event) {
		
			
			
		if (!this._hasFocus) {			


			// show that it's been focused upon
			Element.removeClassName(this._editorContainer, this.settings.cssPrefix + 'editorContainer_Blur');
			Element.addClassName(this._editorContainer, this.settings.cssPrefix + 'editorContainer_Focus');
		
			Refresh.Web.CurrentFreeTextBox = this;
			
			this._hasFocus = true;			

			// blur all other targets
			if (this._toolbars.length > 0) {
				for (var i=0; i<this._toolbars.length; i++) {
					if (this._toolbars[i]._editor && this._toolbars[i]._editor != this)
						this._toolbars[i]._editor.blur();

					this._toolbars[i]._editor = this;
				}
			}	

			if (this._mode == FTB_MODE_DESIGN) {
	
				// re-select text
				if (this._bookmark) {
					this.selectBookmark(this._bookmark);
				}
				
				if (event) this._onEvent(event);
			}			
		}
	},
	
  	blur: function() {
		
		if (this._hasFocus)  {
			this._hasFocus = false;
			this._onDesignBlur();
		}
  	},	
	
	_onDesignBlur: function(event) {
		this.quickSaveData();

		Element.removeClassName(this._editorContainer, this.settings.cssPrefix + 'editorContainer_Focus');
		Element.addClassName(this._editorContainer, this.settings.cssPrefix + 'editorContainer_Blur');

		this._hasFocus = false;
	},	

	_onSubmit: function(event) {
		if (event != null) {
			var form = Event.element(event);
			if (form != null && form.ftbSubmit)
				form.ftbSubmit();
		
			this.saveData();
		}
		
		// text area must be visible for Safari to submit
		this._designEditor.style.width = 0;
		this._designEditor.style.height = 0;
		this._codeEditor.style.display = '';
	},

	_onEvent: function(event) {
		if (!event) {
			return;
		}
				
		if (!this._hasFocus) {
			this._onDesignFocus(event);
			return;
		}

		if (event) {
			event.ftb = this;
			
			// check for user added event listeners
			var listeners = this._addedEvents[event.type];
			
			if (listeners != null) {
				for (var i=0; i<listeners.length; listeners++) {					
					var r = listeners[i](event);
					if (r.cancelBubble == true)
						return;				
				}		
			} else {
				
			}	
		}

		this._typingEvent = false;
		
		window.isDblClick = (event.type == 'dblclick');			
		
		if (event && event.type.indexOf('key') == 0) {

			if (event.type == 'keydown') {
				// TAB
				if (event.keyCode == Event.KEY_TAB && !event.shiftKey) {

					switch (this.settings.tabMode) {
						default:
						case FTB_TABMODE_EXIT:
							
							
							if (this.nextElement) {
								Event.stop(event);
								this.nextElement.focus();
								//this.blur();
								return false;								
							}
							
							// fall through to spaces if there is no tab index
						case FTB_TABMODE_INSERTSPACES:
							Event.stop(event);
							this.insertHtml('&nbsp;&nbsp;&nbsp;&nbsp;');							
							break;
							
						case FTB_TABMODE_NONE:
							// do nothing
							break;							
					}

				// SHIFT+TAB
				} else if (event.keyCode == Event.KEY_TAB && event.shiftKey) {
					
					
					
					if (this.settings.tabMode == FTB_TABMODE_EXIT) {
						if (this.prevElement) {
							Event.stop(event);
							this.prevElement.focus();
							//this.blur();
							return false;								
						}													
					}
					
				// Enter
				} else if (event.keyCode == Event.KEY_RETURN && !event.ctrlKey) {

					if (this.browser.isGecko) {

						if (this.settings.breakMode == FTB_BREAKMODE_P) {

							
							
						}

					} else  if (this.browser.isIE) {

						if (this.settings.breakMode == FTB_BREAKMODE_BR) {

							var sel = this.getSelection();
							var rng = this.createRange(sel);
							
							if (this.tagMatch(rng.parentElement(),'li'))
								return true;									
									
							Event.stop(event);
							
							rng.pasteHTML("<br />");
							rng.collapse(false);
							rng.select();																		
							
							return false;
						}

					} else {

						
					}

				// CTRL+Enter
				} else if (event.keyCode == Event.KEY_RETURN && event.ctrlKey) {

					if (this.browser.isGecko) {

						if (this.settings.breakMode == FTB_BREAKMODE_BR) {
							
						}

					} else  if (this.browser.isIE) {

						if (this.settings.breakMode == FTB_BREAKMODE_P) {
							var sel = this.getSelection();
							var rng = this.createRange(sel);
							
							if (this.tagMatch(rng.parentElement(),'li'))
								return true;									
									
							Event.stop(event);
							
							rng.pasteHTML("<br />");
							rng.collapse(false);
							rng.select();																		
							
							return false;							
						}				

						

					} else {

						
					}


				// Ctrl+V
				} else if (event.keyCode == FTB_EVENTCHAR_PASTE && event.ctrlKey) {

					

				// Ctrl+P
				} else if (event.keyCode == FTB_EVENTCHAR_PRINT && event.ctrlKey) {

										
					
				// UNDO (z)
				} else if (event.keyCode == FTB_EVENTCHAR_UNDO && event.ctrlKey) {

					Event.stop(event);
										
					this.undo();
					return false;

				// REDO (y)
				} else if (event.keyCode == FTB_EVENTCHAR_REDO && event.ctrlKey) {

					Event.stop(event);
					this.redo();
					return false;

				// Ctrl+B
				} else if (event.keyCode == FTB_EVENTCHAR_BOLD && event.ctrlKey) {
					
					Event.stop(event);
					

					Refresh.Web.EditorCommands.execute(this, 'Bold');
					return false;
					
				// Ctrl+I
				} else if (event.keyCode == FTB_EVENTCHAR_ITALIC && event.ctrlKey) {

					Event.stop(event);
					Refresh.Web.EditorCommands.execute(this, 'Italic');
					return false;

				// Ctrl+U
				} else if (event.keyCode == FTB_EVENTCHAR_UNDERLINE && event.ctrlKey) {

					Event.stop(event);
					Refresh.Web.EditorCommands.execute(this, 'Underline');
					return false;
					
				} else {
					// normal typing happened
					if (!event.ctrlKey) {
						this._typingEvent = true;
					}
				}
			} // keydown

		} // key*

		// store caret
		if (event && (event.type == 'keyup' || event.type == 'mouseup') ) {
			console.log('saving bookmark');
			this._bookmark = this.getBookmark();
			
		}

		if (this._pauseTimeoutID) {
			clearInterval(this._pauseTimeoutID);
			delete this._pauseTimeoutID;
		}

		
		
		this._pauseTimeoutID = setTimeout(this._event_onPauseTimeout, this.settings.toolbarUpdateInterval);
	},

	addChangeListener: function(method) {
		this._changeEvents[this._changeEvents.length] = method;
	},

	onPauseTimeout: function() {
		
		
		if (this._pauseTimeoutID) {
			clearInterval(this._pauseTimeoutID);
			delete this._pauseTimeoutID;
		}

		if (this._typingEvent)
			this._addUndoStep('typing');

		// fire all registered methods
		for (var i=0; i<this._changeEvents.length; i++) {
			this._changeEvents[i](this);
		}

		this.quickSaveData();


		this.updateWordCount();
		this.updateToolbars();
	},

	updateWordCount: function() {
		if (this._status == null) return;

		var docWordCount = Refresh.Utility.getNodeWordCount(this._getDocument().body);
		var selWordCount = 0;
		var sel = this.getSelection();
		if (this.browser.isIE) {
			selWordCount = Refresh.Utility.getTextWordCount(this.createRange(sel).text);
		} else {
			selWordCount = Refresh.Utility.getTextWordCount(sel);
        }
		this._status.innerHTML = Refresh.Web.Localization.getValue('statusWords',this.settings.language) + ': ' + ((selWordCount > 0) ? + selWordCount + '/' : '') + docWordCount;
	},

	handleDesignModeTabClick: function(event) {
		this.goToDesignMode();
	},

	handleCodeModeTabClick: function(event) {
		this.goToCodeMode();
	},
	/**
	* Swaps modes
	* @alias Refresh.Web.FreeTextBox.prototype.goToDesignMode
	*/ 
	goToDesignMode: function() {

		if (this._mode == FTB_MODE_DESIGN) return;

		if (this.settings.isFullDocument) {
			var html = this._storeUrls(this._codeEditor.value);
			this._designEditor.contentWindow.document.designMode = 'off';
			this._designEditor.contentWindow.document.designMode = 'on';
			
			this._designEditor.contentWindow.document.open();
			this._designEditor.contentWindow.document.write(html);
			this._designEditor.contentWindow.document.close();
												
		} else {
			this._designEditor.contentWindow.document.body.innerHTML = this._storeUrls(this._codeEditor.value);
		}

		this._codeEditor.style.width = '0px';
		this._codeEditor.style.height = '0px';
		//this._codeEditor.style.display = 'none';

		this._designEditor.style.width = this.settings.width; //'100%';
		this._designEditor.style.height = this.settings.height; //'100%';

		this._mode = FTB_MODE_DESIGN;

		this._designEditor.contentWindow.document.designMode = 'On';

		if (!this.browser.isOpera)
			this._designEditor.contentWindow.document.contentEditable = true;
		if (this.browser.isGecko)
			this._designEditor.contentWindow.document.execCommand("useCSS",null,true);

		// change focus events
		// remove Code editor
		//Event.stopObserving(this._codeEditor, 'focus', this._event_onDesignFocus);	
		//Event.stopObserving(this._codeEditor, 'blur', this._event_onDesignBlur);	

		// add regular editor
		if (this.browser.isIE) 
			Event.observe(this._designEditor.contentWindow.document.body, 'blur', this._event_onDesignBlur);
		else if (this.browser.isOpera) 
			Event.observe(this._designEditor.contentWindow.document, 'blur', this._event_onDesignBlur);
		else 
			Event.observe(this._designEditor.contentWindow, 'blur', this._event_onDesignBlur);	
			
		Element.addClassName(this._codeTab, 'editorTab_Off');
		Element.removeClassName(this._codeTab, 'editorTab_On');
		Element.addClassName(this._designTab, 'editorTab_On');
		Element.removeClassName(this._designTab, 'editorTab_Off');


		this._addUndoStep("From code mode");

		this.focus();
	},
	
	goToCodeMode: function() {
		if (this._mode == FTB_MODE_CODE) return;				
		
		// FULL DOCUMENT MODE
		// 					

		var html = '';
		
		if (this.settings.isFullDocument) {
			html = this.settings.docType + '\n' + 
				Refresh.Web.HtmlCleaner.validateNode( this._designEditor.contentWindow.document.getElementsByTagName('html')[0], this.settings.isFullDocument, this.settings.autoFormat, true );			
		} else {
			html = Refresh.Web.HtmlCleaner.validateNode(this._designEditor.contentWindow.document.body, this.settings.isFullDocument, this.settings.autoFormat, true);			
		}

		this._codeEditor.value = html;
		
		this._designEditor.style.width = 0;
		this._designEditor.style.height = 0;

		this._codeEditor.style.display = '';
		this._codeEditor.style.width = this.settings.width;
		this._codeEditor.style.height = this.settings.height;

		this._mode = FTB_MODE_CODE;
		
		// change focus events
		// Event.observe(this._codeEditor, 'focus', this._event_onDesignFocus);	
		// Event.observe(this._codeEditor, 'blur', this._event_onDesignBlur);
		
		// remove events
		if (this.browser.isIE) 
			Event.stopObserving(this._designEditor.contentWindow.document.body, 'blur', this._event_onDesignBlur);
		else if (this.browser.isOpera) 
			Event.stopObserving(this._designEditor.contentWindow.document, 'blur', this._event_onDesignBlur);
		else 
			Event.stopObserving(this._designEditor.contentWindow, 'blur', this._event_onDesignBlur);	
		
		Element.removeClassName(this._codeTab, 'editorTab_Off');
		Element.addClassName(this._codeTab, 'editorTab_On');
		Element.removeClassName(this._designTab, 'editorTab_On');
		Element.addClassName(this._designTab, 'editorTab_Off');

		this.focus();
	},
	
	quickSaveData: function() {
		if (this._mode == FTB_MODE_DESIGN) {
			var html = this.getQuickHtml();
			this._codeEditor.value = html;
		} else {
			// TODO: validate existing HTML
			// For now, allow submission of invalidated code
		}
	},	
	
	saveData: function() {
		if (this._mode == FTB_MODE_DESIGN) {
			var html = this.getHtml();
			this._codeEditor.value = html;
		} else {
			// TODO: validate existing HTML
			// For now, allow submission of invalidated code
		}
	},
	
	executeCommand: function(commandName, commandValue) {
		if (this._mode != FTB_MODE_DESIGN) return;
	
		if (!commandValue) commandValue == '';
		
		if (!this._hasFocus)
			this.focus();

		try {
			this._getDocument().execCommand(commandName, '', commandValue);
		} catch (e) {
			;;;console.error(commandName,commandValue,e.message);
		}
		
		// record undo
		if (commandName != 'undo' && commandName != 'redo')
			this._addUndoStep(commandName + ((commandValue != '') ? ': ' + commandValue : ''));

		this.quickSaveData();		
		
		this._onEvent( {type:'command'} );

	},

	queryCommandState: function(commandName) {
		if (this._mode != FTB_MODE_DESIGN) return null;
		
		var commandState = null;
		try {
			var commandState = this._getDocument().queryCommandState(commandName,null,null);
		} catch (e) {
			;;;console.error('command state error', commandName);
		}

		if (commandName == "justifyleft" && !commandState) {
			commandState = !(
				this._getDocument().queryCommandState("justifyright",null,null) ||
				this._getDocument().queryCommandState("justifycenter",null,null) ||
				this._getDocument().queryCommandState("justifyfull",null,null) );
		}

		if (commandState == true) {
			return FTB_BUTTONSTATE_HIGHLIGHT;
		} else {
			return FTB_BUTTONSTATE_NORMAL;
		}	
		return;	
	},

	queryCommandValue: function(commandName) {
		if (this._mode != FTB_MODE_DESIGN) return null;

		if (commandName == 'fontfaceslist') {
			commandName = 'fontname';
		} else if (commandName == 'fontsizeslist') {
			commandName = 'fontsize';
		} else if (commandName == 'formatslist') {
			commandName = 'formatBlock';
		}

		var value = null;

		try {
			value = this._designEditor.contentWindow.document.queryCommandValue(commandName);
		} catch (e) {}

		if (value != null) 
			value = new String(value).toLowerCase();
		
		if (commandName.indexOf('color') > -1 && value != '') {
			
			if (this.browser.isIE || !isNaN(value))
				value = Refresh.Utility.intToHexColor(value);
			else if (this.browser.isOpera || value.toString().indexOf('rgb') > -1)
				value = Refresh.Utility.rgbStringToHex(value);
		}		

		if (value == "" && commandName == "fontname")
			value = "Times";
		else if (value == "" && commandName == "fontsize")
			value = "3";
		else if (value == "" && commandName == "forecolor")
			value = "#000000";
		else if (commandName == "formatBlock" && (value == "" || value == "p") )
			value = "normal";

		return value;
	},

	updateToolbars: function() {
	
		if (this._toolbars == null) return;

		if (this._toolbars.length != null) {
			for (var i=0; i<this._toolbars.length; i++) {
				var toolbar = this._toolbars[i];

				if (toolbar) {
					toolbar._editor = this;					
					toolbar.update(this);
				}
			}
		}

		if (this._pauseTimeoutID)
			clearInterval(this._pauseTimeoutID);
	},

	associateToolbar: function(toolbar) {
		if (!this._toolbars) this._toolbars = [];
	
		if (this._toolbars.indexOf(toolbar) == -1)
			this._toolbars.push(toolbar);
	},

	_getDocument: function() {
		return this._getWindow().document;
	},
	
	_getWindow: function() {
		return this._designEditor.contentWindow;
	},	

	/* Start: Old Node Selection code */


	getSelection: function() {
	
		var sel;
		var win = this._getWindow();
		var doc = this._getDocument();
		if (win.getSelection) {
			
			sel = win.getSelection();
		
		} else if (doc.selection) { // should come last; Opera!
		
			sel = doc.selection;
		}
		
		return sel;
		
	
	
		if (this.browser.isIE) {
			return this._getDocument().selection;
			/*
		} else if (this.browser.isSafari) {
					
			var sel = this._designEditor.contentWindow.getSelection();

			// new versions of WebKit have this
			if (sel.getRangeAt != null)
				return sel;
				
			fsel = {};		
			fsel.focusNode = sel.baseNode;
			fsel.focusOffset = sel.baseOffset;
			fsel.anchorNode = sel.extentNode;
			fsel.anchorOffset = sel.extentOffset;
			fsel.text = "" + sel;
			fsel.sel = sel;
			fsel.toString = function () {return this.text;};
			fsel.getRangeAt = function(t) {
				var range = {};
	
				range.startContainer = this.focusNode;
				range.endContainer = this.anchorNode;
				range.commonAncestorContainer = this.focusNode;
				range.createContextualFragment = function (f) {						
					if (f.charAt(0) == '<') {
						var el = doc.createElement("div");		
						el.innerHTML = f;
						return el.firstChild;
					}								
				};
				range.deleteContents = function () {
					doc.execCommand("Delete", false, "");
				};
	
				return rng;
			};
				
			return fsel;
	
		*/
		} else if (this.browser.isGecko || this.browser.isOpera) {
			var sel = this._designEditor.contentWindow.getSelection();
			return sel;		
		} else if (this.browser.isSafari) {
			var sel = this._designEditor.contentWindow.getSelection();
			//var sel = window.getSelection();
			console.log('window',sel);
			return sel;
		}
	},

	getRange: function() {
	
		var sel = this.getSelection();
		return this.createRange(sel);
	},
	
	createRange: function(sel) {
		
		if (sel.createRange) {
			return sel.createRange();
		} else if (sel.getRangeAt) {
			return sel.getRangeAt(0);
		} else { // Safari!
			var range = this._getDocument().createRange();
			//range.setStart(sel.anchorNode, sel.anchorOffset);
			//range.setEnd(sel.focusNode, sel.focusOffset);
			return range;
		}
		
		
		if (this.browser.isIE)
			return sel.createRange();
						
		if (this.browser.isGecko || this.browser.isOpera || this.browser.isSafari) {
			if (typeof sel != "undefined") {
				try {
					return sel.getRangeAt(0);
				} catch(e) {
					
					return this._getDocument().createRange();
				}
			} else {
				return this._getDocument().createRange();
			}
		}
	},

	getBookmark: function() {
		
		var sel = this.getSelection();
		var rng = this.createRange(sel);
		bookmark = {selection: sel, range: rng};
						
		if (this.browser.isGecko) {
			bookmark.range = bookmark.range.cloneRange();
		}
			
		console.log('getting bookmark', bookmark);

		return bookmark;
	},

	selectBookmark: function(bookmark) {
		
		if (this.browser.isIE) {
		
			bookmark.range.select();
		
		} else if ( this.browser.isSafari2 ) {
		
			var selection = bookmark.selection;
			var range = bookmark.range;
			
			var selection = this.getSelection();
			var range = this._getDocument().createRange();
			
			bookmark.range.setStart(bookmark.selection.anchorNode, bookmark.selection.anchorOffset);
			bookmark.range.setEnd(bookmark.selection.focusNode, bookmark.selection.focusOffset);			
			

			return;
			selection.setBaseAndExtent(
				bookmark.selection.anchorNode, 
				bookmark.selection.anchorOffset, 
				bookmark.selection.anchorNode, 
				bookmark.selection.anchorOffset+1);
		} else {
		
			// since gecko doesn't loose the focus in the iframe, ignore the "Saved" bookmark and just select the text
			var range = this._getDocument().createRange();
			var sel = this.getSelection();
		
			// gecko only selection code
			range.setStart(bookmark.range.startContainer, bookmark.range.startOffset);
			range.setEnd(bookmark.range.endContainer, bookmark.range.endOffset);
			
			sel.removeAllRanges();
			sel.addRange(range);		
		}
	},

	surroundHtml: function(start,end) {
		if (this._mode == FTB_MODE_CODE)
			return;
			
		this.focus();

		if (this.browser.isIE) {
			var sel = this._getDocument().selection.createRange();
			html = start + sel.htmlText + end;
			sel.pasteHTML(html);
			
		} else {
			
	        selection = this.getSelection();
	        if (selection) {
	            range = selection.getRangeAt(0);
	        } else {
	            range = this._getDocument().createRange();
	        }

	        this.insertHtml(start + selection + end);
		}
	},
	
	surround: function(tagName, params) {
		var doc = this._getDocument();
		var sel = this.getSelection();

		var fragment  = doc.createDocumentFragment();
		
		// Create range before selection
		var preSelectionRange = doc.createRange();
		preSelectionRange.setStart(sel.anchorNode, 0);
		
		// When text is selected via double-click, Safari jacks the offsets
		// so we need to detect the double-click and adjust accordingly.
		preSelectionRange.setEnd(sel.anchorNode, window.isDblClick ? sel.anchorOffset - 2 : sel.anchorOffset);
		
		// Create the range for the selection
		var range = this._getDocument().createRange();
		range.setStart(sel.anchorNode, sel.anchorOffset);
		range.setEnd(sel.focusNode, sel.focusOffset);
		
		// Create range after selection
		var postSelectionRange =doc.createRange();
		
		// When text is selected via double-click, Safari jacks the offsets
		// so we need to detect the double-click and adjust accordingly.
		postSelectionRange.setStart(sel.focusNode, window.isDblClick ? sel.focusOffset + 2 : sel.focusOffset);
		postSelectionRange.setEnd(sel.focusNode, sel.focusNode.nodeValue.length);
		
		// Create the new 'wrap' tag
		var wrapper = doc.createElement(tagName);
		for (prop in params)
		{
		  wrapper[prop] = params[prop];     
		}
		wrapper.appendChild(doc.createTextNode(sel));
		
		//---------------------------------------------------
		// Append the 3 nodes to the document fragment in
		// consecutive order
		//---------------------------------------------------
		fragment.appendChild(doc.createTextNode(preSelectionRange.toString()));
		fragment.appendChild(wrapper);
		fragment.appendChild(doc.createTextNode(postSelectionRange.toString()));
		
		//---------------------------------------------------
		// Replace the text node containing the selection with
		// the document fragment that we've prepared.
		//---------------------------------------------------
		sel.anchorNode.parentNode.replaceChild(fragment, sel.anchorNode.parentNode.childNodes[0]);

	
	},

	insertHtml: function(html) {
		if (this._mode != FTB_MODE_DESIGN)
			return;
		this.focus();

		if (this.browser.isIE) {
			sel = this._getDocument().selection.createRange();
			sel.pasteHTML(html);
		} else {

	        selection = this._designEditor.contentWindow.getSelection();
			if (selection) {
				range = selection.getRangeAt(0);
			} else {
				range = editor.document.createRange();
			}

	        var fragment = this._getDocument().createDocumentFragment();
	        var div = this._getDocument().createElement("div");
	        div.innerHTML = html;

	        while (div.firstChild) {
	            fragment.appendChild(div.firstChild);
	        }

	        selection.removeAllRanges();
	        range.deleteContents();

	        var node = range.startContainer;
	        var pos = range.startOffset;

	        switch (node.nodeType) {
	            case 3:
	                if (fragment.nodeType == 3) {
	                    node.insertData(pos, fragment.data);
	                    range.setEnd(node, pos + fragment.length);
	                    range.setStart(node, pos + fragment.length);
	                } else {
	                    node = node.splitText(pos);
	                    node.parentNode.insertBefore(fragment, node);
	                    range.setEnd(node, pos + fragment.length);
	                    range.setStart(node, pos + fragment.length);
	                }
	                break;

	            case 1:
	                node = node.childNodes[pos];
	                node.parentNode.insertBefore(fragment, node);
	                range.setEnd(node, pos + fragment.length);
	                range.setStart(node, pos + fragment.length);
	                break;
	        }
	        selection.addRange(range);
		}
	},

	tagMatch: function(item,tagName) {
		if (!item) return null;
		if (item.tagName.search(tagName)!=-1) {
			return item;
		}
		if (item.tagName=='BODY') {
			return false;
		}
		item=item.parentElement;
		return this.tagMatch(item,tagName);
	},

	getParentElement: function() {

		var sel = this.getSelection();
		var range = this.createRange(sel);
		if (this.browser.isIE) {
			switch (sel.type) {
			    case "Text":
			    case "None":
					return range.parentElement();
			    case "Control":
					return range.item(0);
			    default:
					return this._designEditor.contentWindow.document.body;
			}
		} else {
			try {
				var p = range.commonAncestorContainer;
				if (!range.collapsed && range.startContainer == range.endContainer &&
					range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes())
					p = range.startContainer.childNodes[range.startOffset];

				while (p.nodeType == 3) {
					p = p.parentNode;
				}
				return p;
			} catch (e) {
				return null;
			}
		}
	},

	insertNodeAtSelection: function(toBeInserted) {
		if (this.browser.isIE) {
			this.focus();

			sel = this._getDocument().selection.createRange();
			sel.pasteHTML(toBeInserted.outerHTML);
		} else {
			var sel = this.getSelection();
			var range = this.createRange(sel);
			// remove the current selection
			sel.removeAllRanges();
			range.deleteContents();
			var node = range.startContainer;
			var pos = range.startOffset;
			switch (node.nodeType) {
			    case 3: // Node.TEXT_NODE
				// we have to split it at the caret position.
				if (toBeInserted.nodeType == 3) {
					// do optimized insertion
					node.insertData(pos, toBeInserted.data);
					range = this._createRange();
					range.setEnd(node, pos + toBeInserted.length);
					range.setStart(node, pos + toBeInserted.length);
					sel.addRange(range);
				} else {
					node = node.splitText(pos);
					var selnode = toBeInserted;
					if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
						selnode = selnode.firstChild;
					}
					node.parentNode.insertBefore(toBeInserted, node);
					this.selectNodeContents(selnode);
				}
				break;
			    case 1: // Node.ELEMENT_NODE
				var selnode = toBeInserted;
				if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
					selnode = selnode.firstChild;
				}
				node.insertBefore(toBeInserted, node.childNodes[pos]);
				this.selectNodeContents(selnode);
				break;
			}
		}
	},

	selectNodeContents: function(node, pos) {
		var range;
		var collapsed = (typeof pos != "undefined");
		if (this.browser.isIE) {
			range = this._getDocument().body.createTextRange();
			range.moveToElementText(node);
			(collapsed) && range.collapse(pos);
			range.select();
		} else {
			var sel = this.getSelection();
			range = this._getDocument().createRange();
			range.selectNodeContents(node);
			(collapsed) && range.collapse(pos);
			sel.removeAllRanges();
			sel.addRange(range);
		}
	},

	selectNextNode: function(el) {
		var node = el.nextSibling;
		while (node && node.nodeType != 1) {
			node = node.nextSibling;
		}
		if (!node) {
			node = el.previousSibling;
			while (node && node.nodeType != 1) {
				node = node.previousSibling;
			}
		}
		if (!node) {
			node = el.parentNode;
		}
		this.selectNodeContents(node);
	},


	selectNodeContents: function(node, pos) {
		var range;
		var collapsed = (typeof pos != "undefined");
		if (this.browser.isIE) {
			range = this._getDocument().body.createTextRange();
			range.moveToElementText(node);
			(collapsed) && range.collapse(pos);
			range.select();
		} else {
			var sel = this.getSelection();
			range = this._getDocument().createRange();
			range.selectNodeContents(node);
			(collapsed) && range.collapse(pos);
			sel.removeAllRanges();
			sel.addRange(range);
		}
	},

	getNearest: function(tagName) {

		var ancestors = this.getAllAncestors();
		var ret = null;
		tagName = ("" + tagName).toLowerCase();
		for (var i=0;i<ancestors.length;i++) {
			var el = ancestors[i];
			if (el) {
				if (el.tagName.toLowerCase() == tagName) {
					ret = el;
					break;
				}
			}
		}
		return ret;
	},

	getAllAncestors: function() {
		var p = this.getParentElement();
		var a = [];
		while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
			a.push(p);
			p = p.parentNode;
		}
		a.push(this._getDocument().body);
		return a;
	},
	/* End: Old Node Selection code */
	
	/* Custom CSS code */
	setCustomCss: function(customCss) {
		
		var customStyleID = this.id + '_CustomCss';
		var doc = this._getDocument();
		
		if (doc.createStyleSheet) {
			// TODO: fix IE Support for injecting CSS		
			//return;
			
			if (doc.styleSheets.length == 0)
				doc.createStyleSheet();
					
			// get the first one without an href!
			var styletag = null;
			for (var i=0; i<doc.styleSheets.length; i++) {
				if (doc.styleSheets[i].href == '') {
					styletag = doc.styleSheets[i];
				}
			}
		
			if (styletag == null) {
				doc.createStyleSheet();	
				styletag = doc.styleSheets[doc.styleSheets.length-1];
				// return;
			}
			
			if (customCss == '') {
				doc.removeStyleSheet(styleTag);
				
				//
				//Element.remove(styleTag);
				//var head = doc.getElementsByTagName('head')[0];
				//head.removeChild(styleTag);
				
			} else {		
				styletag.cssText = customCss;
			}
		
		} else {
			var styleTag = this._getDocument().getElementById(customStyleID);
			
			if (styleTag == null) {
				styleTag = doc.createElement('style');
				styleTag.ID = customStyleID;			
				doc.getElementsByTagName('head')[0].appendChild(styleTag);
			}
			styleTag.innerHTML = customCss;	
		}	
	},
	
	getCustomCss: function(value) {
		var customStyleID = this.id + '_CustomCss';
		
		if(this.Browser.IsIE){
			return null;
			
			return (doc.styleSheets.length == 0) ? '' : doc.styleSheets[doc.styleSheets.length - 1].cssText;
		
		} else if (this.Browser.IsMozilla) {
			var styleTag = doc.getElementById(customStyleID);
			return (styleTag == null) ? '' : styleTag.innerHTML;
		}		
	},

	getCssClass: function() {
		var parent = this.getParentElement();
		return parent.className;	
	},
	
	setCssClass: function(className	) {
		// retrieve parent element of the selection
		var parent = this.getParentElement();
								
		if (parent && parent.tagName.toLowerCase() == "span") {
			if (parent.childNodes.length == 1) {
				parent.className = className;
				surround = false;
				this.updateToolbars();
				return;
			}
		} else {
			this.surroundHtml("<span class='" + className + "'>", "</span>");
		}	
	},
	
	
	// EVENTS
	addEventListener: function(name, method) {
		name = name.toLowerCase();
		
		if (this._addedEvents[name] == null) {
			this._addedEvents[name] = [];
		}
		this._addedEvents[name].push(method);
	},
	
	_addedEvents: null
	
};

